using System;
using System.Collections.Generic;
using Microsoft.Practices.ObjectBuilder2;
using Common.Core;

namespace Common.Unity.Extensions.Configuration
{
	class ReflectionObjectConfigurationStrategy : BuilderStrategy
	{
		public override void PreBuildUp(IBuilderContext context)
		{
			if ( context.BuildKey is NamedTypeBuildKey )
			{
				NamedTypeBuildKey key = (NamedTypeBuildKey)context.BuildKey;
				List<Type> cache = ResolveCache( context );
				if ( !cache.Contains( key.Type ) )
				{
					IObjectConfiguratorPolicy policy = BuilderPolicyHelper.EnsurePolicy<IObjectConfiguratorPolicy, ObjectConfiguratorPolicy>( context );
					foreach ( IObjectConfigurator configurator in ResolveConfigurators( context ) )
					{
						policy.Configurators.Add( configurator );
					}
					cache.Add( key.Type );
				}
			}
			base.PreBuildUp(context);
		}

		static List<Type> ResolveCache( IBuilderContext context )
		{
			List<Type> result = context.Locator.Get<List<Type>>( typeof(ReflectionObjectConfigurationStrategy) );
			if ( result == null )
			{
				context.Locator.Add( typeof(ReflectionObjectConfigurationStrategy), result = new List<Type>() );
				context.Lifetime.Add( result );
			}
			return result;
		}

		static IEnumerable<IObjectConfigurator> ResolveConfigurators( IBuilderContext context )
		{
			if ( context.BuildKey is NamedTypeBuildKey )
			{
				NamedTypeBuildKey key = (NamedTypeBuildKey)context.BuildKey;
				ObjectConfiguratorAttribute[] attributes = key.Type.GetAttributes<ObjectConfiguratorAttribute>();
				foreach ( ObjectConfiguratorAttribute attribute in attributes )
				{
					IBuilderContext cloned = context.CloneForNewBuild( new NamedTypeBuildKey( attribute.ObjectConfiguratorType ), null );
					IObjectConfigurator item = (IObjectConfigurator)context.Strategies.ExecuteBuildUp( cloned );
					yield return item;
				}
			}
		}
	}
}